import SDK from 'sxran-tool-sdk/Index'
import XeBase from 'sxran-tool-core/lib/XeBase';



/**
 * 额外单独引用一下，使得这个js可以单独使用。
 * @type {Index}
 */
const sdk = new SDK();

// let _this = null
// WS内容
let connect = null;
let connectUrl = null; // ws的url
const failedReconnectTime = 3000 // 失败重连时间
let connectLocking = false; // 连接锁机制
//
let broadcastChannel = null; // 不对外暴露使用。
const broadcastKey = "sxran-im-broadcast";
const userInfoKey = "im-login-userInfo";
export default {
    onopenCallback : function () {},
    // 接收从外部传入的this，并赋给_this
    // receive(vm) {
    //     _this = vm
    // },
    /**
     * 广播通知的key
     */
    getBroadcastKey(){
        return broadcastKey;
    },
    /**
     * 登陆状态。 是ok的。
     */
    loginState(){
        return this.getSelfUser();
    },
    /**
     * 获得登陆之后的用户信息。
     * @returns {*}
     */
    getSelfUser(){
        return sdk.storageUtil.getItem(userInfoKey);
    },
    /**
     * 获得登陆之后的用户id。
     * @returns String
     */
    getSelfUserId(){
        return this.getSelfUser().id;
    },
    // broadcastChannel : sdk.broadcastChannelUtil.getBroadcastChannel(broadcastKey),
    /**
     * 将有的sdk的内容放进来。
     * @param sdk
     * @see #init
     */
    copySdk(sdk){
        this.init(sdk.webSocketUtil,sdk.broadcastChannelUtil,sdk.storageUtil);
    },
    /**
     * 初始化
     * @param webSocketImpl
     * @param broadcastChannelImp
     * @param storageImp
     */
    init(webSocketImpl,broadcastChannelImp,storageImp){
        sdk.setApi(SDK.BASE_NAME,new XeBase());
        sdk.setApi(SDK.WEBSOCKET_NAME,webSocketImpl);
        sdk.setApi(SDK.BROADCAST_CHANNEL_NAME,broadcastChannelImp);
        sdk.setApi(SDK.STORAGE_NAME,storageImp);
    },
    /** 判断是否是群聊
     *
     */
    isGroup(conversation){
        if(conversation.type){
            return conversation.type == 1;
        }else{
            // 兼容,没有type的群组内容。
            return conversation.id.startsWith('1_');
        }
    },
    /**
     * 判断是否是连接的。
     */
    isConnect(){
        return connect;
    },
    // 失败重连机制
    reConnect() {
        console.log('触发了重连未执行')
        if (connectLocking) return;
        connectLocking = true;
        console.log('触发了重连')
        this.connect(connectUrl);
        // CommonUtil.delayTime(this.failedReconnectTime).then(() => {
        //     console.log('触发了延时开启')
        //     this.websocketConnect(true)
        // })
    },
    /**
     * 连接ws
     * @param wsUrl
     */
    async connect(wsUrl){
        connectUrl = wsUrl;
        const that = this;
        this.close();
        broadcastChannel = sdk.broadcastChannelUtil.getBroadcastChannel(broadcastKey); // 不对外暴露使用。
        //
        let websocketConfig = {
            "wsUrl" : wsUrl,
            onclose : () =>{
                that.handLog('onclose');
                that.reConnect();
            },
            onerror: () =>{
                that.handLog('onerror');
                that.reConnect();
            },
            onmessage: (mes) =>{
                let mesObj = sdk.toStringJSON(mes);
                that.handLog('onmessage-接收到的im信息为:',mesObj);
                // 内置的业务逻辑处理
                const data = mesObj.data;
                const command = mesObj.command;
                if(data){
                    switch (command) {
                        case -5: // 登陆的用户信息缓存。
                            // sdk.storageUtil.setItem(userInfoKey,data);
                            break;
                        default :
                            break;
                    }
                }else{
                    that.handError("IM的返回的失败信息:",{command,mes});
                }

                // 发送广播消息，可以使用额外的增强扩展。
                // this.broadcastChannel.postMessage(mesObj);
                broadcastChannel.postMessage(mesObj);
            },
            onopen: () => {
                that.handLog('onopen');
                this.onopenCallback();
                connectLocking = false;
            }
        };
        connect = await sdk.webSocketUtil.connect(websocketConfig);
    },
    /**
     * 处理日志
     * @param tag
     * @param logObj
     */
    handLog(tag,logObj){
        console.log(tag,logObj);
    },
    /**
     * 处理错误异常
     * @param tag
     * @param errObj
     */
    handError(tag,errObj){
        console.error(tag,errObj);
    },
    /**
     * 删除租户的标识。 获取原系统的内容。
     * @param id
     * @returns {*}
     */
    dumpTenant(id){
        let res = id.substring( id.indexOf( ':') + 1 );
        return res;
    },
    /**
     *
     * 发送通用的消息。
     * 【通过回调形式改成，形成 请求/响应 模型 】
     * 【仅仅只是发送的时候，性能较好】
     * @param data [对应json对象]
     * @param callback [对应的data数据] 需要和对应的command保持一致。
     * @see #sendAsync 如果确认一定有返回值可以用它。
     */
    send(data,callback){
        if(callback){
            let broadcast = sdk.broadcastChannelUtil.getBroadcastChannel(broadcastKey);
            // broadcast.setOnMessageOnceCall((res)=>{ // 如果有延迟就会接受不到对应的数据
            broadcast.setOnMessageCall((res)=>{
                if( Math.abs(res.command)   === Math.abs(data.cmd) ){
                    callback(res);
                    broadcast.close();
                }
            });
        }
        connect.send(sdk.baseUtil.toJSONString(data));
    },
    /**
     * 设置监听器函数内容。
     * @param commands
     * @param callback
     */
    setMonitor(commands,callback){
        if(callback){
            let broadcast = sdk.broadcastChannelUtil.getBroadcastChannel(broadcastKey);
            // broadcast.setOnMessageOnceCall((res)=>{ // 如果有延迟就会接受不到对应的数据
            broadcast.setOnMessageCall((res)=>{
                if( commands.includes(res.command) ){
                    callback(res);
                }
            });
        }
    },
    /**
     * http的ws模型响应内容
     * @param data
     * @returns {Promise<unknown>}
     */
    sendAsync(data){
        return new Promise((resolve, reject) => {
            try{
                connect.send(sdk.baseUtil.toJSONString(data));
                let broadcast = sdk.broadcastChannelUtil.getBroadcastChannel(broadcastKey);
                broadcast.setOnMessageCall((res)=>{
                    if( Math.abs(res.command)   === Math.abs(data.cmd) ){
                        resolve(res);
                        broadcast.close();
                    }
                });
            }catch (e) {
                // 客户端发送失败。
                reject(e);
            }
        });

    },
    /**
     * 手动关闭消息通道。
     */
    close(){
        connect?.close();
        if(broadcastChannel){
            broadcastChannel.close();
        }
    },
    //////////////////////////////////////////////////////
    //
    //                 以下是通过 sendAsync 获取的业务操作功能。 类似于http的接口形式：
    //      1. go开头代表没有返回值，仅仅只是后台处理。
    //      2. 其他默认都是有返回值操作的。
    //////////////////////////////////////////////////////
    /**
     * 心跳
     */
    goHeartbeat(){
        this.send({cmd: 13, hbbyte: "-127"});
    },
    /**
     * 鉴权操作
     * @param token
     * @param extras
     */
    goAuth(token,extras){
        this.send({cmd: 3, token,extras});
    },
    /**
     * 获取指定用户基础信息。
     * @since uni-im
     * @param userId 用户的id
     * @param type 0:在线, 1:离线, 2:所有用户(在线+离线)
     * @param extras   额外参数
     * @returns {*}
     */
    getUserInfo(userId,type,extras){
         return this.sendAsync({cmd: 17, type,userId : this.dumpTenant(userId),extras});
    },
    /**
     * 获取群组详细信息;
     * @param groupId
     * @returns {*|Promise<unknown>}
     */
    getGroupInfo(groupId){
        return this.sendAsync({cmd: 20, groupId });
    },
    /**
     * 获取群组在线用户列表请求; 【 在线：代表绑定群组，并且进入了群组 】
     * @param groupId
     * @returns {*|Promise<unknown>}
     */
    getGroupOnlineUsers(groupId){
        return this.sendAsync({cmd: 21, groupId });
    },
    /**
     * 获取指定用户的消息。
     * @param fromUserId 用户的id
     * @param type 0:离线消息,1:历史消息
     * @param offset 分页偏移量
     * @param count 分页数量
     * @param beginTime 消息区间开始时间
     * @param endTime 消息区间结束时间
     * @param extras   额外参数
     * @returns {*}
     */
    getUserMessage(fromUserId,type,offset,count, beginTime,endTime,extras){
        return this.sendAsync({cmd: 19, type,fromUserId,userId : this.getSelfUserId() ,offset,count, beginTime,endTime,extras});
    },
    /**
     * 获取指定群组的消息。
     * @param groupId 群组id
     * @param type 0:离线消息,1:历史消息
     * @param offset 分页偏移量
     * @param count 分页数量
     * @param beginTime 消息区间开始时间
     * @param endTime 消息区间结束时间
     * @param extras   额外参数
     * @returns {*}
     */
    getGroupMessage(groupId,type,offset,count, beginTime,endTime,extras){
        return this.sendAsync({cmd: 19, type,groupId,userId : this.getSelfUserId(),offset,count, beginTime,endTime,extras});
    },
    /**
     * 执行私聊
     * @param data 目标数据
     * @returns {*} 可能被后台处理过发送的消息内容
     */
    doChat(data){
        data.cmd = 11;
        data.createTime = data.createTime || new Date().getTime() ;
        data.from = data.from || this.getSelfUser().id ;
        return this.sendAsync(data);
    },
    /**
     * 获得会话的消息列表。
     * @param data 输入自己需要的额外参数逻辑，可以不传
     * @returns {*}
     */
    getMessageList(data = {}){
        data.cmd = 22;
        return this.sendAsync( data );
    },
    /**
     * 获取会话列表。
     * @since uni-im
     * @param data 输入自己需要的额外参数逻辑，可以不传
     * @returns {*}
     */
    getConversationList(data = {}){
        data.cmd = 23;
        return this.sendAsync( data );
    },
    /**
     * 搜索用户列表的接口。
     * @param data 输入自己需要的额外参数逻辑，可以不传
     * @returns {*}
     */
    searchUserList(data = {}){
        data.cmd = 24;
        return this.sendAsync( data );
    },
    /**
     * 搜索群组列表的接口。
     * @param data 输入自己需要的额外参数逻辑，可以不传
     * @returns {*}
     */
    searchGroupList(data = {}){
        data.cmd = 25;
        return this.sendAsync( data );
    },
    /**
     * 已读通知处理。
     * @param uuid 唯一id
     * @returns {*}
     */
    readNotification(uuid){
        let data = {
            uuid,
            cmd : 27,
            toId : this.getSelfUserId()
        };
        return this.sendAsync( data );
    },
    /**
     * 获取通知列表。
     * @since uni-im
     * @param data 通知的id
     * @returns {*}
     */
    getNotificationList(data = {}){
        data.cmd = 28;
        return this.sendAsync( data );
    },
    /**
     * 添加好友申请。
     * @param data 输入自己需要的额外参数逻辑，可以不传
     * @returns {*}
     */
    addFriendInvite(data){
        data.cmd = 29;
        return this.sendAsync( data );
    },

    /**
     * 同意好友申请请求。
     * @param fromUid uuid标识。
     * @param message 回复消息。
     * @returns {*}
     */
    acceptFriendApplication(fromUid , message){
        let data = {
            cmd : 30,
            fromUid , message
        }
        return this.sendAsync( data );
    },
    /**
     * 拒绝好友申请请求。
     * @param fromUid 对应的用户id。
     * @param message 回复消息。
     * @returns {*}
     */
    refuseFriendApplication(fromUid , message){
        let data = {
            cmd : 31,
            fromUid , message
        }
        return this.sendAsync( data );
    },
    /**
     * 生成会话id。
     * @param chatType 对应的用户id。
     * @param originalTo 回复消息。
     * @returns {*}
     */
    generateConversationId(chatType,originalTo){
        let data = {
            cmd : 32,
            chatType , originalTo
        }
        return this.sendAsync( data );
    },
    /**
     * 清除未读数量。
     * @since uni-im
     * @param conversationId
     * @returns {Promise<unknown>}
     */
    clearUnreadCount(conversationId){
        // 先设置为已读，再调用后端接口。
        let data = {
            cmd : 33,
            id : conversationId,
            userId : this.getSelfUserId()
        }
        return this.sendAsync( data );
    },
    /**
     * 获取好友列表
     * @since uni-im
     * @param friend_uid 具体的好友id。
     * @param keyword 搜索关键词
     * @returns {Promise<unknown>}
     */
    getFriendList(friend_uid,keyword){
        let data = {
            cmd : 34,friend_uid,keyword
        }
        return this.sendAsync( data );
    },
    /**
     * 获取群组列表
     * uni-im最大500条。
     * @since uni-im
     * @returns {Promise<unknown>}
     */
    getGroupList(group_id){
        let data = {
            cmd : 35,group_id
        }
        return this.sendAsync( data );
    },


    /**
     * 添加群组申请。
     * @param data 输入自己需要的额外参数逻辑，可以不传
     * @returns {*}
     */
    addGroupInvite(data){
        data.cmd = 36;
        return this.sendAsync( data );
    },
    /**
     * 同意好友申请请求。
     * @param uuid uuid标识。
     * @param message 回复消息。
     * @returns {*}
     */
    acceptGroupApplication(userId,groupId , message){
        let data = {
            cmd : 37,
            userId  ,
            groupId ,
            message
        }
		console.log('---acceptGroupApplication-----',data);
        return this.sendAsync( data );
    },
    /**
     * 拒绝好友申请请求。
     * @param uuid 对应的用户id。
     * @param message 回复消息。
     * @returns {*}
     */
    refuseGroupApplication(userId,groupId , message){
        // 先设置为已读，再调用后端接口。
        let data = {
            cmd : 38,
            userId ,
            groupId  ,
            message
        }
        return this.sendAsync( data );
    },
    /**
     * 创建群聊请求
     * @param data
     * @returns {Promise<unknown>}
     */
    createGroup(data){
        data.cmd = 39;
        return this.sendAsync( data );
    },
	/**
	 * 删除好友请求
	 * @param friendUid 好友id
	 * @returns {Promise<unknown>}
	 */
	deleteFriend(friendUid){
        let data = {
			cmd : 40,
            friendUid
		}
	    return this.sendAsync( data );
	},
    /**
     * 修改群组信息
     * @param data 群组
     * @returns {Promise<unknown>}
     */
    updateGroupInfo(data){
        data.cmd = 41;
        return this.sendAsync( data );
    },
    /**
     * 解散群聊
     * @param groupId 群组id
     * @returns {Promise<unknown>}
     */
    disBandGroup(groupId){
        return this.sendAsync( {groupId,cmd:42} );
    },
    /**
     * 退出群聊
     * @param groupId 群组id
     * @returns {Promise<unknown>}
     */
    exitGroup(groupId){
        return this.sendAsync( {groupId,cmd:43} );
    },
    /**
     * 移出群聊
     * @param groupId 群组id
     * @param users 用户id
     * @returns {Promise<unknown>}
     */
    exportGroup(groupId,users){
        return this.sendAsync( {groupId,users,cmd:44} );
    },
    /**
     * 删除消息
     * @param msgId 消息id
     * @returns {Promise<unknown>}
     */
    deleteMessage(msgId){
        return this.sendAsync( {id:msgId,cmd:45} );
    },
    /**
     * 撤回消息
     * @since uni-im
     * @param msgId 群组id
     * @returns {Promise<unknown>}
     */
    revokeMsg(msgId){
        return this.sendAsync( { id : msgId , cmd:46 } );
    },
    /**
     * WebRTC对offer的发送通知
     * @param msgId 群组id
     * @returns {Promise<unknown>}
     */
    webRtcOffer(data){
        return this.sendAsync( { ...data , cmd:47 } );
    },
    /**
     * WebRTC对 answer 的发送通知
     * @param msgId 群组id
     * @returns {Promise<unknown>}
     */
    webRtcAnswer(data){
        return this.sendAsync( { ...data , cmd:48 } );
    },
    /**
     * 添加往后台会话数据。
     * @since uni-im
     * @param conversationData
     */
    addConversationData(conversationData) {

    },
    /**
     * 获得群组的成员列表。
     * uniIm给的是1千条。
     * @since uni-im
     * @param group_id
     */
    getGroupMember(group_id) {

    },
    /**
     * 设置推送的客户端id
     * @since uni-im
     * @param pushClientId
     */
    setPushCid(pushClientId){

    },
    /**
     * 根据本地会话的最大更新时间，查询云端数据
     * @since uni-im
     * @param maxConversationUpdateTime
     */
    getMsgListByMaxConversationUpdateTime(maxConversationUpdateTime){
        return this.getMessageList();
    }
}
